前一篇有提到,RRSIG 紀錄裡面,會有記載「涵蓋數量」。DNSSEC 一開始並不支持 *
號(萬用字元),而且若一有萬用字元的紀錄,代表說,需要對無限多個紀錄做簽署的動作。
要講解這個之前,必須要講解一下 DNS 如何處理 *
的狀況。
一個使用萬用字元的 DNS 紀錄,會長得像這個樣子。
*.example.com. 3600 IN MX 10 host1.example.com.
當查詢 host.example.com
時,DNS 會「合成」一條紀錄,返回 host1.example.com
給對方。另外,萬用字元只會在 DNS 找不到其他紀錄時,才會有效。
例如:
www.example.com. 3600 IN A 10 1.1.1.1
*.example.com. 3600 IN A 10 2.2.2.2
這時候,若查詢 www.example.com
,會返回 1.1.1.1
而不是 2.2.2.2
。反過來說,查詢 notexist.example.com
,則返回 2.2.2.2
。
這邊因為對於一些詞彙的定義有些混亂,所以我花了不少時間來研究這一點。
關於細節,可以參考 RFC4034 的第七頁。
假設當你啟用 DNSSEC,又有用了萬用字元。
你的設定是:
*.example.com. 3600 IN A 10 2.2.2.2
查詢 a.example.com
時,A 的部分是返回以上那筆,所以沒有問題。可是 DNSSEC 會同時需要看 RRSIG,但又因為萬用字元會「合成」不存在的紀錄出來,我們取回這份紀錄時,拿回的 RRSIG 會是對應到 *.example.com
的,因此會不知道要去找誰的 DNSKEY。
DNSSEC 的處理方式,是在 RRSIG 裡面記錄「這筆 RRSIG 原本是給誰用的」,實際上是紀錄「我有幾個 label」
這個 label 的計算方式是這樣子的:
.
號來做區分*
.
不算是 label
所以像是 *.example.com
的 RRSIG 紀錄,其「涵蓋數量」欄位會是寫上 2。這時候,接受方就會知道,這個 RRSIG 是對應到一筆萬用字元的紀錄,所以會去找上一級的 DNSKEY,即 example.com
的 DNSKEY 紀錄。
另外,根據 RFC4035,使用萬用字元的狀況下,也要附上一個 NSEC,來證明真的沒有這個紀錄。
通常來說,除非攻擊者非常有耐心,不然不太可能知道一個網域下所有的 DNS 紀錄(扣除直接黑了那台 DNS 伺服器的狀況)。這也能提供某種方面上的保護,畢竟只要取了一個很長的名字,然後一群人就搞小圈圈,只有他們知道這個名字。再來惡搞一下,弄個 14 字英文字的網域名稱,別人要連線,得先猜 6.71*10^19 次,猜到天荒地老。
總之,DNS 原本這種沒有辦法得知全部紀錄的特性,某方面上也是安全的。畢竟你知道正確的網域名稱,別人連要連上去都不知道要打什麼網域,更不用提防禦了。
不過前一篇提到,NSEC 會帶來安全性的疑慮。是因為:
所以攻擊者只要從 A 開始窮舉,一直讓伺服器回 NSEC,就可以窮舉所有的紀錄了。因為這會有很大的問題,加上部分網域商會因此不使用 DNSSEC,於是後來就出現了 NSEC3。
NSEC3 的運作方式和 NSEC 相同,但是把內容改成經過 SHA-1 計算的值,所以還是可以證明說「真的有下一筆紀錄」。由於 SHA-1 目前還是安全的,所以也不用擔心會因此被窮舉所有的紀錄。
經過這麼多解說,DNSSEC 聽起來很棒。不過,目前還不是每個 DNS 都有支持 DNSSEC,有可能是因為:
不過,目前看來,DNSSEC 仍然是潮流。